home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / quicspool / libglob / glob.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  4KB  |  224 lines

  1. static char *rcs= "$Header: glob.c,v 1.1 88/01/15 12:15:45 simpson Rel $";
  2. /*
  3. $Log:    glob.c,v $
  4.  * Revision 1.1  88/01/15  12:15:45  simpson
  5.  * initial release
  6.  * 
  7.  * Revision 0.1  87/12/11  17:18:05  simpson
  8.  * beta test
  9.  * 
  10. */
  11. #include "glob.h"
  12.  
  13. #define SLOP 5
  14. #define MAX_SET 0177
  15.  
  16. /* control codes for regular expression evaluation */
  17. #define PATTERN_ANY '?'
  18. #define PATTERN_CHARACTER 'X'
  19. #define PATTERN_END '$'
  20. #define PATTERN_SET '['
  21. #define PATTERN_SET_MEMBER 'M'
  22. #define PATTERN_SET_RANGE '-'
  23. #define PATTERN_STAR '*'
  24.  
  25. /*
  26.  * Examples (=> denotes `compiles into')
  27.  *
  28.  *    a    =>    Xa
  29.  *    ?    =>    ?
  30.  *    [x0-9]    =>    [^EMx-09    (^E is control-E)
  31.  *    *    =>    *
  32.  *    END    =>    $
  33.  *
  34.  *    a?[x0-9]* => Xa?[^EMx-09*$
  35.  */
  36.  
  37. glob_compile (pattern, buffer)
  38. char *pattern;
  39. char *buffer;    /* compiled pattern */
  40. {
  41.     char *x;    /* pointer into compiled pattern */
  42.     int c;
  43.     int result;
  44.  
  45.     if (pattern == 0 || pattern[0] == 0)
  46.         return(GLOB_PATTERN_EMPTY);
  47.  
  48.     x = buffer;
  49.     while (x < &buffer[GLOB_MAX_PATTERN - SLOP]) {
  50.         c = *pattern++;
  51.         if (c == 0) {
  52.             *x++ = PATTERN_END;
  53.             return(GLOB_OK);
  54.         }
  55.  
  56.         switch (c) {
  57.         case '?':
  58.             *x++ = PATTERN_ANY;
  59.             continue;
  60.  
  61.         case '[':
  62.             if ((result = compile_set(pattern, x, &buffer[GLOB_MAX_PATTERN - SLOP])) < 0)
  63.                 return(result);
  64.             pattern += result + 1;
  65.             x += x[1] + 2;
  66.             continue;
  67.  
  68.         case '*':
  69.             *x++ = PATTERN_STAR;
  70.             continue;
  71.  
  72.         default:
  73.             *x++ = PATTERN_CHARACTER;
  74.             *x++ = c;
  75.             continue;
  76.         }
  77.     }
  78.     return(GLOB_PATTERN_TOO_BIG);
  79. }
  80.  
  81. int glob_execute (pattern, s)
  82. char *pattern;    /* compiled pattern */
  83. char *s;    /* string to be matched against */
  84. {
  85.     char *current;
  86.     int result;
  87.  
  88.     for (;;)
  89.         switch (*pattern++) {
  90.         case PATTERN_ANY:
  91.             if (*s++)
  92.                 continue;
  93.             return(0);
  94.  
  95.         case PATTERN_CHARACTER:
  96.             if (*pattern++ == *s++)
  97.                 continue;
  98.             return(0);
  99.  
  100.         case PATTERN_END:
  101.             return(*s == 0);
  102.  
  103.         case PATTERN_SET:
  104.             if ((result = in_set(pattern, *s++)) == 1) {
  105.                 pattern += *pattern + 1;
  106.                 continue;
  107.             }
  108.             return(result);
  109.  
  110.         case PATTERN_STAR:
  111.             current = s;
  112.             while (*s++)
  113.                 continue;
  114.             do {
  115.                 s--;
  116.                 if (result = glob_execute(pattern, s))
  117.                     return(result);
  118.             } while (s > current);
  119.             return(0);
  120.  
  121.         default:
  122.             return(GLOB_EXECUTION_ERROR);
  123.         }
  124. }
  125.  
  126. int glob_match (pattern, s)
  127. char *pattern;
  128. char *s;
  129. {
  130.     int result;
  131.     char buffer[GLOB_MAX_PATTERN];
  132.  
  133.     if ((result = glob_compile(pattern, buffer)) < 0)
  134.         return(result);
  135.     else
  136.         return(glob_execute(buffer, s));
  137. }
  138.  
  139. /* returns 1 if character c is member of set and 0 otherwise */
  140. static int in_set (set, c)
  141. char *set;    /* compiled set pattern */
  142. char c;
  143. {
  144.     int n;
  145.  
  146.     if (c == 0)
  147.         return(0);
  148.     n = *set++;
  149.     while (n > 0)
  150.         switch (*set++) {
  151.         case PATTERN_SET_MEMBER:
  152.             if (*set++ == c)
  153.                 return(1);
  154.             n -= 2;
  155.             continue;
  156.  
  157.         case PATTERN_SET_RANGE:
  158.             if (*set++ <= c && c <= *set++)
  159.                 return(1);
  160.             n -= 3;
  161.             continue;
  162.  
  163.         default:
  164.             return(GLOB_EXECUTION_ERROR);
  165.         }
  166.     return(0);
  167. }
  168.  
  169. #define IS_RANGE(s) (s[1] && s[2] && s[1] == '-' && s[2] != ']')
  170.  
  171. /* compiles a set returning the number of pattern characters consumed */
  172. static int compile_set (pattern, x, limit)
  173. char *pattern;
  174. char *x;
  175. char *limit;
  176. {
  177.     char *slot;    /* size of set goes here */
  178.     int size;    /* number of bytes in compiled set */
  179.     char *start = pattern;
  180.  
  181.     if (*pattern == 0)
  182.         return(GLOB_BRACKET_MISSING);
  183.  
  184.     *x++ = PATTERN_SET;
  185.     slot = x++;
  186.     size = 0;
  187.  
  188.     if (IS_RANGE(pattern)) {
  189.         if (pattern[0] > pattern[2])    /* pattern[1] == '-' */
  190.             return(GLOB_RANGE_INVERTED);
  191.         *x++ = PATTERN_SET_RANGE;
  192.         *x++ = pattern[0];
  193.         *x++ = pattern[2];
  194.         pattern += 3;
  195.         size += 3;
  196.     } else {
  197.         *x++ = PATTERN_SET_MEMBER;
  198.         *x++ = *pattern++;
  199.         size += 2;
  200.     }
  201.  
  202.     while (*pattern != ']' && x < limit) {
  203.         if (*pattern == 0)
  204.             return(GLOB_BRACKET_MISSING);
  205.         if (IS_RANGE(pattern)) {
  206.             if (pattern[0] > pattern[2])    /* pattern[1] == '-' */
  207.                 return(GLOB_RANGE_INVERTED);
  208.             *x++ = PATTERN_SET_RANGE;
  209.             *x++ = pattern[0];
  210.             *x++ = pattern[2];
  211.             pattern += 3;
  212.             size += 3;
  213.         } else {
  214.             *x++ = PATTERN_SET_MEMBER;
  215.             *x++ = *pattern++;
  216.             size += 2;
  217.         }
  218.     }
  219.     if (size > MAX_SET)
  220.         return(GLOB_SET_TOO_BIG);
  221.     *slot = size;
  222.     return(pattern - start);
  223. }
  224.